package com.fulu.game.bi.service.impl.channel;

import cn.hutool.core.collection.CollectionUtil;
import com.fulu.game.bi.common.exception.BizException;
import com.fulu.game.bi.common.util.lang.StringUtils;
import com.fulu.game.bi.entity.bo.channel.LabelAndKeywordsBO;
import com.fulu.game.bi.entity.bo.channel.LabelBO;
import com.fulu.game.bi.entity.enums.GroupRelTableEnum;
import com.fulu.game.bi.entity.enums.LabelStatusEnum;
import com.fulu.game.bi.entity.po.auth.BiUser;
import com.fulu.game.bi.entity.po.channel.GroupRel;
import com.fulu.game.bi.entity.po.channel.Label;
import com.fulu.game.bi.entity.po.channel.LabelKeywords;
import com.fulu.game.bi.entity.vo.channel.label.LabelDisplayVO;
import com.fulu.game.bi.entity.vo.channel.label.LabelQueryVO;
import com.fulu.game.bi.entity.vo.channel.label.LabelSaveVO;
import com.fulu.game.bi.enums.CommonlyOrderEnums;
import com.fulu.game.bi.mysql.bi.channel.GroupRelDao;
import com.fulu.game.bi.mysql.bi.channel.LabelGroupDao;
import com.fulu.game.bi.mysql.playadmin.channel.LabelDao;
import com.fulu.game.bi.mysql.playadmin.channel.LabelKeywordsDao;
import com.fulu.game.bi.redis.service.auth.BiUserService;
import com.fulu.game.bi.redis.service.channel.LabelService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Slf4j
public class LabelServiceImpl implements LabelService {

    @Autowired
    private BiUserService biUserService;

    @Autowired
    private LabelDao labelDao;

    @Autowired
    private LabelKeywordsDao labelKeywordsDao;

    @Autowired
    private GroupRelDao groupRelDao;

    @Autowired
    private LabelGroupDao labelGroupDao;

    @Override
    @Transactional
    public Label save(LabelSaveVO vo) {
        if (Objects.isNull(vo.getId())) {
            return createNewLabel(vo);
        }

        return updateExistLabel(vo);
    }

    private Label updateExistLabel(LabelSaveVO vo) {
        Date now = new Date();
        BiUser currentUser = biUserService.getCurrentUser();

        List<LabelAndKeywordsBO> boList = labelDao.findLabelAndKeywordsBOByKeywordsAndIdNot(vo.getKeywords(), vo.getId());
        checkKeywordsRule(vo, boList);
        Label label = new Label();
        BeanUtils.copyProperties(vo, label);
        label.setAdminId(currentUser.getId());
        label.setAdminName(currentUser.getName());
        label.setUpdateTime(now);
        if (labelDao.updateSelective(label) < 1) {
            throw new BizException("修改失败");
        }
        labelKeywordsDao.deleteByLabelId(label.getId());
        batchSaveLabelKeywords(vo, label.getId());

        bindRel(vo, label);

        return label;
    }

    private Label createNewLabel(LabelSaveVO vo) {
        Date now = new Date();
        BiUser currentUser = biUserService.getCurrentUser();

        if (labelDao.countByName(vo.getName()) > 0) {
            throw new BizException("标签名重复");
        }
        vo.setShouldEdit(true);

        List<LabelAndKeywordsBO> boList = labelDao.findLabelAndKeywordsBOByKeywords(vo.getKeywords());
        checkKeywordsRule(vo, boList);
        Label label = new Label();
        BeanUtils.copyProperties(vo, label);
        label.setAdminId(currentUser.getId());
        label.setAdminName(currentUser.getName());
        label.setCreateTime(now);
        label.setUpdateTime(now);

        if (labelDao.insert(label) < 1) {
            throw new BizException("新增失败");
        }

        batchSaveLabelKeywords(vo, label.getId());
        log.info("新增标签： {}", label);

        bindRel(vo, label);

        return label;
    }

    private void bindRel(LabelSaveVO vo, Label label) {
        if (vo.getShouldEdit()) {
            Integer labelId = label.getId();
            groupRelDao.deleteByRelId(labelId, GroupRelTableEnum.LABEL.getName());

            if (CollectionUtil.isNotEmpty(vo.getGroupIdList())) {
                List<GroupRel> relList = vo.getGroupIdList().stream()
                        .map(Integer::parseInt)
                        .map(groupId -> {
                            GroupRel rel = new GroupRel();
                            rel.setGroupId(groupId);
                            rel.setRelId(labelId);
                            return rel;
                        })
                        .collect(Collectors.toList());

                groupRelDao.insert(relList, GroupRelTableEnum.LABEL.getName());
            }
        }
    }

    private void batchSaveLabelKeywords(LabelSaveVO vo, Integer labelId) {
        List<LabelKeywords> labelKeywordList = vo.getKeywords().stream()
                .filter(StringUtils::isNotEmpty)
                .map(map -> {
                    LabelKeywords labelKeywords = new LabelKeywords();
                    labelKeywords.setLabelId(labelId);
                    labelKeywords.setKeywords(map);
                    return labelKeywords;
                }).collect(Collectors.toList());
        labelKeywordsDao.insertList(labelKeywordList);
    }

    private void checkKeywordsRule(LabelSaveVO labelModifyDTO, List<LabelAndKeywordsBO> boList) {
        if (!boList.isEmpty()) {
            if (labelModifyDTO.getStatisticsBeginTime() == null && labelModifyDTO.getStatisticsEndTime() == null) {
                throw new BizException(String.format("搜索词《%s》已存在", boList.get(0).getKeywords()));
            }
            boList.forEach(bo -> {
                if (bo.getStatisticsEndTime() != null && bo.getStatisticsBeginTime() != null) {
                    long originStartTime = bo.getStatisticsBeginTime().getTime();
                    long originEndTime = bo.getStatisticsEndTime().getTime();
                    long targetStartTime = labelModifyDTO.getStatisticsBeginTime().getTime();
                    long targetEndTime = labelModifyDTO.getStatisticsEndTime().getTime();
                    //判断时间上是否存在交集
                    if (originStartTime >= targetStartTime && originStartTime <= targetEndTime
                            || originStartTime <= targetStartTime && originEndTime >= targetEndTime
                            || originEndTime >= targetStartTime && originEndTime <= targetEndTime) {
                        throw new BizException(String.format("搜索词《%s》已存在", bo.getKeywords()));
                    }
                } else {
                    throw new BizException(String.format("搜索词《%s》已存在", bo.getKeywords()));
                }
            });
        }
    }


    @Override
    public PageInfo<LabelDisplayVO> list(LabelQueryVO vo) {
        LabelBO labelBO = LabelQueryVO.convertToBO(vo);
        //如果存在关键词搜索，需要先确定labelId
        if (StringUtils.isNotEmpty(vo.getKeyword())) {
            List<Integer> labelIds = labelKeywordsDao.findLabelIdByKeywordsLike(vo.getKeyword());
            if (labelIds.isEmpty()) {
                return new PageInfo();
            }
            labelBO.setLabelIds(labelIds);
        }
        PageHelper.startPage(vo.getPageNum(), vo.getPageSize(), CommonlyOrderEnums.CREATE_DESC.getValue());
        List<Label> labels = labelDao.findByParameter(labelBO);
        PageInfo<Label> page = new PageInfo(labels);
        List<LabelDisplayVO> labelVOS = page.getList().stream().map(map -> {
            LabelDisplayVO labelVO = new LabelDisplayVO();
            BeanUtils.copyProperties(map, labelVO);
            labelVO.setKeywords(labelKeywordsDao.findKeywordsByLabelId(map.getId()));
            labelVO.setStatus(LabelStatusEnum.VALID.getType());
            if (map.getStatisticsBeginTime() != null && map.getStatisticsEndTime() != null) {
                if (System.currentTimeMillis() < map.getStatisticsBeginTime().getTime()) {
                    labelVO.setStatus(LabelStatusEnum.INVALID.getType());
                } else if (System.currentTimeMillis() > map.getStatisticsEndTime().getTime()) {
                    labelVO.setStatus(LabelStatusEnum.EXPIRE.getType());
                }
            }
            return labelVO;
        }).collect(Collectors.toList());
        PageInfo<LabelDisplayVO> pageVo = new PageInfo();
        BeanUtils.copyProperties(page, pageVo);
        labelVOS.forEach(v -> {
            List<GroupRel> groupRelList = groupRelDao.findByRelId(v.getId(), GroupRelTableEnum.LABEL.getName());
            if (CollectionUtil.isNotEmpty(groupRelList)) {
                List<Integer> groupIdList = groupRelList.stream()
                        .map(GroupRel::getGroupId)
                        .collect(Collectors.toList());
                List<String> name = labelGroupDao.findNameByIds(groupIdList);
                v.setGroupNameList(name);
                v.setGroupIdList(groupIdList);
            }
            BiUser user = Optional.ofNullable(biUserService.findById(v.getAdminId())).orElse(new BiUser());
            v.setAdminName(user.getName());
        });
        pageVo.setList(labelVOS);
        return pageVo;
    }
}
